//sudo apt-get install build-essential libgl1-mesa-dev libglu1-mesa-dev freeglut3-dev libsdl1.2-dev libsdl-image1.2-dev libsdl-mixer1.2-dev libsdl-ttf2.0-dev libsdl-gfx1.2-dev libsoil-dev
//在Framework目录下执行 ./build.sh
//wsad qe ikjl uo 控制摄像机 esc 退出

#include "headers.h"
#include "userfuncs.h"

int done;
SDL_Event event;
int lockFrameAdjust = 0;

static struct Posture state = {
    {0, 0, 0},
    {0, 0, 0},
    0};
static struct Posture stateAcc = {
    {0, 0, 0},
    {0, 0, 0},
    0};

#define ang_t 0.01745329251994329576923690768489

int render()
{
    static clock_t begin = clock();
    if (RENDER_LOCK_FRAME > 0)
    {
        if ((clock() - begin) < (1000000 / RENDER_LOCK_FRAME))
        {
            return 0;
        }
        else
        {
            Renderfps = getRenderFps();
            begin = clock();
        }
    }
    else
    {
        Renderfps = getRenderFps();
    }

    glClearColor(0.0, 0.0, 0.0, 1.0);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    if (DOUBLE_EYES == 0)
    {
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        gluPerspective(FOV, (((float)(screen->w) / ((float)screen->h))), REN_NEAR, REN_FAR);
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
        gluLookAt(0, 0, 0, 0, 0, -1, 0, 1, 0);
        glRotatef(state.dir[0], 0, -1, 0);
        glRotatef(state.dir[1], (-1) * cos(state.dir[0] * ang_t), 0, sin(state.dir[0] * ang_t));
        glRotatef(state.dir[2], cos((state.dir[0] + 90) * ang_t), tan(state.dir[1] * ang_t), (-1) * sin((state.dir[0] + 90) * ang_t));
        glTranslatef((-1) * (state.pos[0]), (-1) * (state.pos[1]), (-1) * (state.pos[2]));
        glColor3f(1, 1, 1);
        onRender();
    }
    else
    {
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        gluPerspective(FOV, (((float)(screen->w / 2) / ((float)screen->h))), REN_NEAR, REN_FAR);
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
        glViewport(0, 0, screen->w / 2, screen->h);
        gluLookAt(-(DOUBLE_EYES / 2), 0, 0, 0, 0, -1, 0, 1, 0);
        glRotatef(state.dir[0], 0, -1, 0);
        glRotatef(state.dir[1], (-1) * cos(state.dir[0] * ang_t), 0, sin(state.dir[0] * ang_t));
        glRotatef(state.dir[2], cos((state.dir[0] + 90) * ang_t), tan(state.dir[1] * ang_t), (-1) * sin((state.dir[0] + 90) * ang_t));
        glTranslatef((-1) * (state.pos[0]), (-1) * (state.pos[1]), (-1) * (state.pos[2]));
        glColor3f(1, 1, 1);
        onRender();
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        gluPerspective(FOV, (((float)(screen->w / 2) / ((float)screen->h))), REN_NEAR, REN_FAR);
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
        glViewport(screen->w / 2, 0, screen->w / 2, screen->h);
        gluLookAt((DOUBLE_EYES / 2), 0, 0, 0, 0, -1, 0, 1, 0);
        glRotatef(state.dir[0], 0, -1, 0);
        glRotatef(state.dir[1], (-1) * cos(state.dir[0] * ang_t), 0, sin(state.dir[0] * ang_t));
        glRotatef(state.dir[2], cos((state.dir[0] + 90) * ang_t), tan(state.dir[1] * ang_t), (-1) * sin((state.dir[0] + 90) * ang_t));
        glTranslatef((-1) * (state.pos[0]), (-1) * (state.pos[1]), (-1) * (state.pos[2]));
        glColor3f(1, 1, 1);
        onRender();
    }
    SDL_GL_Enter2DMode();
    if (DOUBLE_EYES == 0)
    {
        glMatrixMode(GL_PROJECTION);
        glPushMatrix();
        glLoadIdentity();
        glOrtho(0.0, (GLdouble)screen->w, (GLdouble)screen->h, 0.0, 0.0, 1.0);
    }
    else
    {
        glMatrixMode(GL_PROJECTION);
        glPushMatrix();
        glLoadIdentity();
        glOrtho(0.0, (GLdouble)screen->w / 2, (GLdouble)screen->h, 0.0, 0.0, 1.0);
    }
    onHUD();
    SDL_GL_Leave2DMode();
    SDL_GL_SwapBuffers();
    if (SDL_Flip(screen) == -1)
        return -1;
    return 0;
}

int mainLoop()
{
    onLoop();
    if (render() != 0)
        return -1;

    if (DISPLAY_TO_TERMINAL)
        printf("%d\n", getFps());
    return 0;
}

int eventLoop()
{
    state.pos[0] += stateAcc.pos[0];
    state.pos[1] += stateAcc.pos[1];
    state.pos[2] += stateAcc.pos[2];
    state.dir[0] += stateAcc.dir[0];
    state.dir[1] += stateAcc.dir[1];
    state.dir[2] += stateAcc.dir[2];

    switch (event.type)
    {
    case SDL_KEYDOWN:
        switch (event.key.keysym.sym)
        {
        case SDLK_ESCAPE:
            done = 1;
            onExit();
            break;
        case SDLK_w:
            stateAcc.pos[2] = -0.1;
            break;
        case SDLK_s:
            stateAcc.pos[2] = 0.1;
            break;
        case SDLK_a:
            stateAcc.pos[0] = -0.1;
            break;
        case SDLK_d:
            stateAcc.pos[0] = 0.1;
            break;
        case SDLK_q:
            stateAcc.pos[1] = -0.1;
            break;
        case SDLK_e:
            stateAcc.pos[1] = 0.1;
            break;
        case SDLK_i:
            stateAcc.dir[1] = 1;
            break;
        case SDLK_k:
            stateAcc.dir[1] = -1;
            break;
        case SDLK_j:
            stateAcc.dir[0] = 1;
            break;
        case SDLK_l:
            stateAcc.dir[0] = -1;
            break;
        case SDLK_u:
            stateAcc.dir[2] = 1;
            break;
        case SDLK_o:
            stateAcc.dir[2] = -1;
            break;
        default:
            break;
        }
        break;
    case SDL_KEYUP:
        switch (event.key.keysym.sym)
        {
        case SDLK_ESCAPE:
            done = 1;
            onExit();
            break;
        case SDLK_w:
            stateAcc.pos[2] = 0;
            break;
        case SDLK_s:
            stateAcc.pos[2] = 0;
            break;
        case SDLK_a:
            stateAcc.pos[0] = 0;
            break;
        case SDLK_d:
            stateAcc.pos[0] = 0;
            break;
        case SDLK_q:
            stateAcc.pos[1] = 0;
            break;
        case SDLK_e:
            stateAcc.pos[1] = 0;
            break;
        case SDLK_i:
            stateAcc.dir[1] = 0;
            break;
        case SDLK_k:
            stateAcc.dir[1] = 0;
            break;
        case SDLK_j:
            stateAcc.dir[0] = 0;
            break;
        case SDLK_l:
            stateAcc.dir[0] = 0;
            break;
        case SDLK_u:
            stateAcc.dir[2] = 0;
            break;
        case SDLK_o:
            stateAcc.dir[2] = 0;
            break;
        default:
            break;
        }
        break;
    default:
        break;
    }
    return 0;
}

int main(int argc, char *argv[])
{
    nefInit();
    glutInit(&argc, argv);
    nefGLinit();
    onSetup();
    done = 0;
    while (!done)
    {
        if (EVENT_LOCK_FRAME > 0)
        {
            Delay_ms(int(1000 / EVENT_LOCK_FRAME) + lockFrameAdjust);
            Neffps = getFps();
        }
        else
        {
            Neffps = getFps();
        }
        if (Neffps > EVENT_LOCK_FRAME)
            lockFrameAdjust++;
        if (Neffps < EVENT_LOCK_FRAME)
            lockFrameAdjust--;

        if (mainLoop() == -1)
            return -1;
        state.pos[0] += stateAcc.pos[0];
        state.pos[1] += stateAcc.pos[1];
        state.pos[2] += stateAcc.pos[2];
        state.dir[0] += stateAcc.dir[0];
        state.dir[1] += stateAcc.dir[1];
        state.dir[2] += stateAcc.dir[2];

        while (SDL_PollEvent(&event))
        {
            eventLoop();
            switch (event.type)
            {
            case SDL_QUIT:
                onExit();
                done = 1;
                break;
            default:
                break;
            }
        }
    }
    clean_up();
}